package org.systm.adminuser.service;

import org.global.basic.BaseServiceOpImpl;
import org.global.basic.CurdFindRepository;
import org.global.utils.BeansUtils;
import org.springframework.stereotype.Service;
import org.systm.adminuser.dao.UserRoleStore;
import org.systm.adminuser.entity.UserPermission;
import org.systm.adminuser.entity.UserRole;
import org.systm.adminuser.params.AcceptUserRole;
import org.systm.adminuser.params.UserRoleParams;
import org.systm.adminuser.service.condition.UserPermissionQuery;
import org.systm.adminuser.service.condition.UserRoleQuery;
import org.systm.menu.entity.Menu;
import org.systm.menu.entity.PageMeta;
import org.systm.menu.service.MenuService;
import org.systm.menu.service.PageMetaService;
import org.systm.menu.service.condition.MenuConditionQuery;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserRoleService extends BaseServiceOpImpl<UserRole, String, UserRoleParams<String>> {

    @Resource
    UserRoleStore userRoleStore;

    @Resource
    EntityManager entityManager;

    @Resource
    MenuService menuService;

    @Resource
    UserPermissionService permissionService;

    @Resource
    PageMetaService pageMetaService;

    @Override
    public CurdFindRepository<UserRole, String> repository() {
        return this.userRoleStore;
    }

    @Override
    public EntityManager entityManger() {
        return this.entityManager;
    }

    @Override
    @Transactional
    public UserRole save(UserRoleParams<String> userRoleParams) {
        UserRole userRole = userRoleParams.getUserRole();
        Objects.requireNonNull(userRole);
        String roleName = userRole.getRole();
        Objects.requireNonNull(roleName);
        if (exists(UserRoleQuery.getByRoleName().apply(roleName))) {
            throw new RuntimeException("角色名已经存在，请更换角色名。");
        }
        return super.save(userRoleParams);
    }

    /**
     * 1.从菜单中提取权限，并更新到角色中。
     * 2.菜单要维护角色名
     * 3.角色中要维护一个菜单列表
     */
    @Override
    @Transactional
    public UserRole update(UserRoleParams<String> userRoleParams) throws IllegalAccessException {
        AcceptUserRole accept = userRoleParams.getAccept();
        if (accept == null) throw new RuntimeException("数据不能为空");
        List<String> menuIds = accept.getMenuIds();
        Optional<UserRole> userRoleOp = findById(accept.getId());
        if (userRoleOp.isEmpty()) throw new RuntimeException("角色不存在");
        UserRole userRole = userRoleOp.get();
        if (menuIds != null) {
            // 1.把权限放到角色中
            updateRolePer(menuIds, userRole);

            // 2.维护菜单的角色列表
            List<String> roleAllMenuId = userRole.getMenuIds();
            Optional<List<Menu>> roleAllMenuOp = menuService.findByIds(roleAllMenuId, String.class);
            String roleName = accept.getRole();

            if (roleAllMenuOp.isPresent()) {
                List<Menu> menus = roleAllMenuOp.get();
                menus = menus.stream()
                        .filter((menu) -> menuIds.stream().noneMatch((m) -> m.equals(menu.getId())))
                        .collect(Collectors.toList());
                List<PageMeta> updateMeta = new ArrayList<>();
                for (Menu menu : menus) {
                    PageMeta meta = menu.getMeta();
                    List<String> roles = meta.getRoles();
                    if (roles != null) {
                        roles.remove(roleName);
                    }
                    updateMeta.add(meta);
                }
                pageMetaService.repository().saveAll(updateMeta);
            }

            Optional<List<Menu>> optionalMenus = menuService.findByIds(accept.getMenuIds(), String.class);
            if (optionalMenus.isPresent()) {
                List<Menu> menus = optionalMenus.get();
                // 获取直接父级ID
                Set<String> pidSet = menus.stream().map(Menu::pid).collect(Collectors.toSet());
                Optional<List<Menu>> pMenuOp = menuService.findByIds(new ArrayList<>(pidSet), String.class);
                if (pMenuOp.isPresent()) {
                    List<Menu> pMenus = pMenuOp.get();
                    List<Menu> stopMenu = pMenus.stream()
                            .filter((pm) -> menus.stream().noneMatch((m) -> pm.getId().equals(m.getId())))
                            .collect(Collectors.toList());
                    menus.addAll(stopMenu);
                }
                List<PageMeta> updateMeta = new ArrayList<>();
                for (Menu menu : menus) {
                    PageMeta meta = menu.getMeta();
                    List<String> roles = meta.getRoles();
                    if (roles != null && !roles.contains(roleName)) {
                        roles.add(roleName);
                    }
                    updateMeta.add(meta);
                }
                pageMetaService.repository().saveAll(updateMeta);
            }

        }

        // 3.把属性都copy到角色中，包括了menuId
        BeansUtils.copy(accept, userRole);
        userRole.setId(accept.getId());
        userRoleParams.set(userRole);
        return super.update(userRoleParams);
    }

    private void updateRolePer(List<String> menuIds, UserRole userRole) {
        Optional<List<Menu>> perOp = menuService.findAll(MenuConditionQuery.findPer.apply(menuIds));
        if (perOp.isPresent()) {
            List<Menu> perMenus = perOp.get();
            List<String> perName = perMenus.stream().map(Menu::getName).collect(Collectors.toList());
            Optional<List<UserPermission>> perNameOp = permissionService.findAll(UserPermissionQuery.perSpecs.apply(perName));
            if (perNameOp.isPresent()) {
                List<UserPermission> userPermissions = perNameOp.get();
                Set<UserPermission> perSet = new HashSet<>(userPermissions);
                userRole.setPermissions(new ArrayList<>(perSet));
            }
        }
    }
}
